// #include "util.hpp"
// #include "level.hpp"
// #include "message.hpp"
// #include "format.hpp"
// #include "sink.hpp"
// #include "logger.hpp"
// #include "buffer.hpp"
// #include <unistd.h>
#include "log.h"

/* 扩展一个以时间作为日志文件滚动切换类型的日志落地模块
    1.以时间进行滚动，其实是以时间段进行滚动
    2.实现思想：以当前系统时间，取模时间段大小，可以得到当前时间段是第几个时间段
        每次以当前系统时间取模，判断当前文件的时间段是否一致，不一致代表不是同一个时间段
    3.时间段划分：1s、1分钟(60s)、1小时(3600s)、1天(3600*24s)，且时间段都会转换为s为单位计算

*/
enum class TimeGap {
    GAP_SECOND,
    GAP_MINUTE,
    GAP_HOUR,
    GAP_DAY
};
class RollByTimeLogSink : public log::LogSink {
public:
    RollByTimeLogSink(const std::string &base_name, TimeGap gap_type) 
        :base_name_(base_name) {
        // 确定时间段
        switch(gap_type) {
            case TimeGap::GAP_SECOND : gap_size_ = 1; break;
            case TimeGap::GAP_MINUTE : gap_size_ = 60; break;
            case TimeGap::GAP_HOUR : gap_size_ = 3600; break;
            case TimeGap::GAP_DAY : gap_size_ = 3600 * 24; break;
            default : assert(false);
        }
        // 创建目录，防止目录不存在
        log::util::File::create_directory(log::util::File::get_path(base_name));
        // 创建文件，根据基础文件名进行创建
        std::string file_name = create_new_file();
        // 打开文件
        ofs_.open(file_name, std::ios::binary | std::ios::app);
        assert(ofs_.is_open());
        // 初始化当前文件的时间段，以1s为时间段时需要特殊处理，不然cur_gap_就一直是0了
        cur_gap_ = gap_size_ == 1 ? log::util::Date::get_time() : log::util::Date::get_time() % gap_size_;

    }
    virtual void log(const char *data, size_t length) override {
        // 获取系统时间，计算时间段，并与当前日志文件时间段比较
        size_t cur = gap_size_ == 1 ? log::util::Date::get_time() : log::util::Date::get_time() % gap_size_;

        if (cur != cur_gap_) {
            ofs_.close();
            std::string file_name = create_new_file();
            ofs_.open(file_name, std::ios::binary | std::ios::app);
            assert(ofs_.is_open());
            cur_gap_ = cur;
        }
        ofs_.write(data, length);
        assert(ofs_.good());
    }
private:
    std::string create_new_file() {
            // 获取系统当前时间戳
            time_t t = log::util::Date::get_time();
            // 转换为时间结构体
            struct tm tt;
            localtime_r(&t, &tt);
            // 拼接为完整文件名
            std::stringstream file_name;
            file_name << base_name_;
            file_name << tt.tm_year + 1900;
            file_name << tt.tm_mon + 1;
            file_name << tt.tm_mday;
            file_name << tt.tm_hour;
            file_name << tt.tm_min;
            file_name << tt.tm_sec;
            file_name << ".log";
            //返回
            return file_name.str();
        }
private:
    std::string base_name_;//基础文件名
    std::ofstream ofs_;//输出文件流
    size_t gap_size_;//时间段大小
    size_t cur_gap_;// 当前文件所处的时间段
};

void test_log() {
    // log::Logger::ptr logger = log::LoggerManager::get_instance().get_logger("async-logger");
    // if (logger.use_count() == 0) return;
    // logger->debug(__FILE__, __LINE__, "%s", "未禾");
    // logger->info(__FILE__, __LINE__, "%s", "未禾");
    // logger->warn(__FILE__, __LINE__, "%s", "未禾");
    // logger->error(__FILE__, __LINE__, "%s", "未禾");
    // logger->fatal(__FILE__, __LINE__, "%s", "未禾");
    
    // size_t count = 0;
    // while (count <= 500000) {
    //     logger->fatal(__FILE__, __LINE__, "测试日志-%d", count++);
    // }

    // log::Logger::ptr logger = log::LoggerManager::get_instance().get_logger("async-logger");
    // if (logger.use_count() == 0) return;
    // logger->debug("%s", "未禾");
    // logger->info("%s", "未禾");
    // logger->warn("%s", "未禾");
    // logger->error("%s", "未禾");
    // logger->fatal("%s", "未禾");
    
    // size_t count = 0;
    // while (count <= 500000) {
    //     logger->fatal("测试日志-%d", count++);
    // }

    log::Logger::ptr logger = log::LoggerManager::get_instance().get_logger("async-logger");
    if (logger.use_count() == 0) return;
    DEBUG_LOG(logger, "%s", "未禾");
    INFO_LOG(logger, "%s", "未禾");
    WARN_LOG(logger, "%s", "未禾");
    ERROR_LOG(logger, "%s", "未禾");
    FATAL_LOG(logger, "%s", "未禾");
    
    size_t count = 0;
    while (count <= 500000) {
        FATAL_LOG(logger, "测试日志-%d", count++);
    }


    // log::Logger::ptr logger = log::LoggerManager::get_instance().get_logger("async-logger");
    // if (logger.use_count() == 0) return;
    // DEBUG("%s", "未禾");
    // INFO("%s", "未禾");
    // WARN("%s", "未禾");
    // ERROR("%s", "未禾");
    // FATAL("%s", "未禾");
    
    // size_t count = 0;
    // while (count <= 200000) {
    //     FATAL("测试日志-%d", count++);
    // }

    
}

int main() {
    /*std::cout << log::util::Date::get_time() << std::endl;
    log::util::File::create_directory("./abc/def/text.txt");
    */
    /*
    std::cout << log::LogLevel::to_string(log::LogLevel::Value::UNKONW) <<  std::endl;
    std::cout << log::LogLevel::to_string(log::LogLevel::Value::DEBUG) <<  std::endl;
    std::cout << log::LogLevel::to_string(log::LogLevel::Value::INFO) <<  std::endl;
    std::cout << log::LogLevel::to_string(log::LogLevel::Value::WARN) <<  std::endl;
    std::cout << log::LogLevel::to_string(log::LogLevel::Value::ERROR) <<  std::endl;
    std::cout << log::LogLevel::to_string(log::LogLevel::Value::FATAL) <<  std::endl;
    std::cout << log::LogLevel::to_string(log::LogLevel::Value::OFF) <<  std::endl;
    */
    // log::LogMsg logmsg;

    // std::shared_ptr<log::FormatItem> ptr = std::make_shared<log::TimeFormatItem>();

    // log::LogMsg msg(log::LogLevel::Value::INFO, "test.cc", 22, "初音未来", "root");
    // log::Formatter formatter;
    // std::string str = formatter.format(msg);
    // std::cout << str << std::endl;

    // log::LogSink::ptr stdout_lsp = log::SinkFactory<log::StdoutLogSink>::create();
    // log::LogSink::ptr file_lsp = log::SinkFactory<log::FileLogSink>::create("./logfile/test.log");
    // log::LogSink::ptr roll_lsp = log::SinkFactory<log::RollBySizeLogSink>::create("./logfile/roll-", 1024 * 1024);

    // log::LogSink::ptr stdout_lsp = log::SinkFactory::create<log::StdoutLogSink>();
    // log::LogSink::ptr file_lsp = log::SinkFactory::create<log::FileLogSink>("./logfile/test.log");
    // log::LogSink::ptr roll_lsp = log::SinkFactory::create<log::RollBySizeLogSink>("./logfile/roll-", 1024 * 1024);
    
    // stdout_lsp->log(str.c_str(), str.size());
    // file_lsp->log(str.c_str(), str.size());

    // size_t cur_fsize = 0;
    // size_t count = 0;
    // while (cur_fsize < 1024 * 1024 * 10) {
    //     std::string tmp = str + std::to_string(count++);
    //     roll_lsp->log(tmp.c_str(), tmp.size());
    //     cur_fsize += tmp.size();
    // }

    // log::LogSink::ptr roll_lsp = log::SinkFactory::create<RollByTimeLogSink>("./logfile/roll-", TimeGap::GAP_SECOND);
    // time_t now = log::util::Date::get_time();
    // while (log::util::Date::get_time() < now + 5) {
    //     log::LogMsg msg(log::LogLevel::Value::INFO, "test.cc", 22, "初音未来", "root");
    //     log::Formatter formatter;
    //     str = formatter.format(msg);
    //     roll_lsp->log(str.c_str(), str.size());
    //     // usleep(1000);
    // }

    // std::string logger_name = "sync-logger-";
    // log::LogLevel::Value limit = log::LogLevel::Value::WARN;
    // log::Formatter::ptr fmt(new log::Formatter);
    // log::LogSink::ptr stdout_ptr(new log::StdoutLogSink);
    // log::LogSink::ptr file_ptr(new log::FileLogSink("./logfile/test.log"));
    // log::LogSink::ptr roll_ptr(new log::RollBySizeLogSink("./logfile/base-", 1024 * 1024));
    // std::vector<log::LogSink::ptr> sinks = { stdout_ptr, file_ptr, roll_ptr };
    // log::Logger::ptr logger(new log::SyncLogger(logger_name, limit, fmt, sinks));
    
    // logger->debug(__FILE__, __LINE__, "%s", "未禾");
    // logger->info(__FILE__, __LINE__, "%s", "未禾");
    // logger->warn(__FILE__, __LINE__, "%s", "未禾");
    // logger->error(__FILE__, __LINE__, "%s", "未禾");
    // logger->fatal(__FILE__, __LINE__, "%s", "未禾");
    
    // size_t cur_fsize = 0;
    // size_t count = 0;
    // while (cur_fsize < 1024 * 1024 * 10) {
    //     logger->fatal(__FILE__, __LINE__, "测试日志-%d", count++);
    //     cur_fsize += 20;
    // }

    // std::unique_ptr<log::LoggerBuilder> builder(new log::LocalLoggerBuilder);
    // builder->build_logger_name("sync-logger");
    // builder->build_Formatter("[%d{%H:%M:%S}]%m%n");
    // builder->build_logger_type(log::LoggerType::SYNC_LOGGER);
    // builder->build_sink<log::StdoutLogSink>();
    // builder->build_sink<log::FileLogSink>("./logfile/test.log");
    // builder->build_sink<log::RollBySizeLogSink>("./logfile/base-", 1024 * 1024);
    // log::Logger::ptr logger = builder->build();
    
    // logger->debug(__FILE__, __LINE__, "%s", "未禾");
    // logger->info(__FILE__, __LINE__, "%s", "未禾");
    // logger->warn(__FILE__, __LINE__, "%s", "未禾");
    // logger->error(__FILE__, __LINE__, "%s", "未禾");
    // logger->fatal(__FILE__, __LINE__, "%s", "未禾");
    
    // size_t cur_fsize = 0;
    // size_t count = 0;
    // while (cur_fsize < 1024 * 1024 * 5) {
    //     logger->fatal(__FILE__, __LINE__, "测试日志-%d", count++);
    //     cur_fsize += 20;
    // }
    
    // // <缓冲区测试
    // // 从文件中读取数据并写入到缓冲区，在从缓冲区读取数据并写入到另一个文件中
    // std::ifstream ifs;
    // ifs.open("./temp/test.log", std::ios::binary);
    // if (!ifs.is_open()) {
    //     std::cout << "test.log file open fail\n";
    //     return -1;
    // }
    // log::Buffer buffer;
    // ifs.seekg(0, std::ios::end);
    // size_t fsize = ifs.tellg();// 获取文件大小
    // ifs.seekg(0, std::ios::beg);
    // std::string body(fsize, 0);
    // ifs.read(&body[0], fsize);
    // if (!ifs.good()) { std::cout << "read error\n"; }
    // ifs.close();
    // for (int i = 0; i < fsize; i++) {
    //     buffer.push(&body[i], 1);
    // }
    
    // std::ofstream ofs;
    // ofs.open("./temp/temp.log", std::ios::binary);
    // if (!ofs.is_open()) {
    //     std::cout << "temp.log file open fail\n";
    //     return -1;
    // }
    // for (int i = 0; i < fsize; i++) {
    //     ofs.write(buffer.begin(), 1);
    //     if (!ofs.good()) { std::cout << "read error\n"; }
    //     buffer.move_reader(1);
    // }
    // ofs.close();
    // // 缓冲区测试>

    // // <局部异步日志器测试>
    // std::unique_ptr<log::LoggerBuilder> builder(new log::LocalLoggerBuilder);
    // builder->build_logger_name("async-logger");
    // builder->build_Formatter("[%c][%d{%H:%M:%S}]%m%n");
    // builder->build_logger_type(log::LoggerType::ASYNC_LOGGER);
    // builder->build_enable_unsafe_async();
    // builder->build_sink<log::StdoutLogSink>();
    // builder->build_sink<log::FileLogSink>("./logfile/test.log");
    // builder->build_sink<log::RollBySizeLogSink>("./logfile/base-", 1024 * 1024);
    // log::Logger::ptr logger = builder->build();
    
    // logger->debug(__FILE__, __LINE__, "%s", "未禾");
    // logger->info(__FILE__, __LINE__, "%s", "未禾");
    // logger->warn(__FILE__, __LINE__, "%s", "未禾");
    // logger->error(__FILE__, __LINE__, "%s", "未禾");
    // logger->fatal(__FILE__, __LINE__, "%s", "未禾");
    
    // size_t count = 0;
    // while (count <= 500000) {
    //     logger->fatal(__FILE__, __LINE__, "测试日志-%d", count++);
    // }
    // // <局部异步日志器测试>

    // <全局异步日志器测试>
    std::unique_ptr<log::LoggerBuilder> builder(new log::GlobalLoggerBuilder);
    builder->build_logger_name("async-logger");
    builder->build_Formatter("[%c][%f:%l][%d{%H:%M:%S}]%m%n");
    builder->build_logger_type(log::LoggerType::ASYNC_LOGGER);
    // builder->build_enable_unsafe_async();
    builder->build_sink<log::StdoutLogSink>();
    builder->build_sink<log::FileLogSink>("./logfile/test.log");
    builder->build_sink<log::RollBySizeLogSink>("./logfile/base-", 1024 * 1024);
    builder->build();
    // logger->debug(__FILE__, __LINE__, "%s", "未禾");
    // logger->info(__FILE__, __LINE__, "%s", "未禾");
    // logger->warn(__FILE__, __LINE__, "%s", "未禾");
    // logger->error(__FILE__, __LINE__, "%s", "未禾");
    // logger->fatal(__FILE__, __LINE__, "%s", "未禾");
    
    // size_t count = 0;
    // while (count <= 500000) {
    //     logger->fatal(__FILE__, __LINE__, "测试日志-%d", count++);
    // }
    test_log();
    // <全局异步日志器测试>
    return 0;
}
